﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sundstrom.Mvvm.Command
{
    public sealed class AsyncRelayCommand<T> : ICommand<T>
    {
        private readonly Func<Task> _execute;
        private readonly Func<T, bool> _canExecute;

        public AsyncRelayCommand(Func<Task> execute, Func<T, bool> canExecute)
        {
            Contract.Requires<ArgumentNullException>(execute != null);
            Contract.Requires<ArgumentNullException>(canExecute != null);

            _execute = execute;
            _canExecute = canExecute;
        }

        public AsyncRelayCommand(Func<Task> execute)
        {

            Contract.Requires<ArgumentNullException>(execute != null);

            _execute = execute;
            _canExecute = null;
        }

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute((T)parameter);
        }

        public Task ExecuteAsync()
        {
            return _execute();
        }

        void ICommand<T>.Execute(T parameter)
        {
            throw new NotSupportedException();
        }

        public bool CanExecute(T parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute((T)parameter);
        }

        void ICommand.Execute(object parameter)
        {
            _execute();
        }

        public event EventHandler CanExecuteChanged;

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}
